#include "MainViewer.h"
#include "Units.h"
#include "Snapping.h"
#include "NodeData.h"
#include "CameraManipulator.h"
#include <QtCore/QUrl>
#include <QtCore/QDir>
#include <QtGUI/QDragEnterEvent>
#include <QtGUI/QDropEvent>
#include <QtGUI/QMessageBox>
#include <osg/ComputeBoundsVisitor>
//#include <osg/Geode>
//#include <osg/ShapeDrawable>
#include <osgGa/TerrainManipulator>
#include <osgViewer/ViewerEventHandlers>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>


MainViewer::MainViewer() : m_pSelectionModel(NULL), m_DragType(Unknown)
{
	setAcceptDrops(true);
//	setCameraManipulator(new CameraManipulator);
    setCameraManipulator(new osgGA::TerrainManipulator);
	addEventHandler(new osgViewer::StatsHandler);

	// TODO: get dimensions from Document.HomeGrid
//	osg::Vec2s dimensions(3, 3);
//	updateHomePosition(dimensions);
//	getCameraManipulator()->home(1.0f);
}


void MainViewer::setModel(SceneManagerModel* model)
{
	m_rSceneManager = model;
	m_rSelectionManager = new SelectionManager(m_rSceneManager.get());
	m_rPickHandler = new PickHandler(m_rSelectionManager.get());
	addEventHandler(m_rPickHandler.get());
	setSceneData( m_rSceneManager->getRoot() );
}


void MainViewer::setItemSelectionModel(QItemSelectionModel* selectionModel)
{
	//TODO: handle multiple calls, even with selectionModel = NULL
	Q_ASSERT(m_pSelectionModel == NULL);
	connect(
		selectionModel, 
		SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
		SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))
	);
	m_rPickHandler->setItemSelectionModel(selectionModel);
}


void MainViewer::dragEnterEvent(QDragEnterEvent *event)
{
	if(event->mimeData()->hasUrls())
	{
		QString filePath = event->mimeData()->urls()[0].toLocalFile();

		if(getFileTypeFromExtension(filePath) == Image)
		{
			m_DragType = Image;
			event->acceptProposedAction();
		}
		else if(getFileTypeFromExtension(filePath) == Model)
		{
            m_DragType = Model;
            event->acceptProposedAction();
		}
		else
		{
			m_DragType = Unknown;
		}
	}
}


void MainViewer::dragLeaveEvent(QDragLeaveEvent *event)
{
	event->accept();
}


void MainViewer::dragMoveEvent(QDragMoveEvent* /*event*/)
{
}


void MainViewer::dropEvent(QDropEvent *event)
{
	QList<QUrl> urls = event->mimeData()->urls();
	QString filePath = event->mimeData()->urls()[0].toLocalFile();
	QDir dir(QDir::current());
	QString relativePath = dir.relativeFilePath(filePath);
	switch(getFileTypeFromExtension(filePath))
	{
	case Image:
		//TODO: Add access to the home grid
		//setGridTexture(relativePath);
		//event->acceptProposedAction();
		break;
	case Model:
        loadAndAddObjectToSceneManager(filePath);
		m_DragType = Unknown;
        event->accept();
		break;
	default:
		QMessageBox::warning(this, tr("d20Grid"), tr("Unable to load:\n") + relativePath);
		break;
	}
}

void MainViewer::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
	foreach( QModelIndex index, deselected.indexes() )
	{
		m_rSelectionManager->remove( m_rSceneManager->node(index) );
	}

	foreach( QModelIndex index, selected.indexes() )
	{
        if(m_rSceneManager->data(index, SceneManagerModel::Selectable).toBool())
        {
            m_rSelectionManager->add( m_rSceneManager->node(index) );
        }
	}
}

void MainViewer::loadAndAddObjectToSceneManager(const QString& filePath)
{
    osg::ref_ptr<osg::PositionAttitudeTransform> newObject = loadNode(filePath);
    osg::ComputeBoundsVisitor cbv;
    newObject->accept(cbv);
    newObject->setScale(osg::Vec3(1.f, 1.f, 1.f) * Units::inchesToMeters(1.f));
    NodeData* pNodeData = new NodeData;
    pNodeData->selectable = m_rSceneManager->rowCount(QModelIndex()) > 0;
    newObject->setUserData(pNodeData);
    newObject->setName( QFileInfo(filePath).baseName().toAscii().data() );
    m_rSceneManager->addObject(SceneManager::Model, newObject.get());
}

void MainViewer::updateHomePosition(const osg::Vec2s& dimensions)
{
	float f = Units::squareSize();
	float x = f * (dimensions.x() / 2);
	float y = f * (dimensions.y() / 2);
	getCameraManipulator()->setHomePosition( osg::Vec3d(x, y, 20), osg::Vec3d(x, y, 0), osg::Y_AXIS );
}


osg::PositionAttitudeTransform* MainViewer::loadNode(const QString &filePath)
{
	osg::Node* pNode = osgDB::readNodeFile(filePath.toStdString());
	if(!pNode)
	{
		return NULL;
	}
    osg::PositionAttitudeTransform* pTransform = new osg::PositionAttitudeTransform;
	pTransform->addChild(pNode);
	return pTransform;
}



MainViewer::FileType MainViewer::getFileTypeFromExtension(const QString& filePath)
{
	QFileInfo info(filePath);
	if(info.suffix() == "bmp") return Image;
	if(info.suffix() == "tga") return Image;
	if(info.suffix() == "tif") return Image;
	if(info.suffix() == "tiff") return Image;
	if(info.suffix() == "png") return Image;
	if(info.suffix() == "jpg") return Image;
	if(info.suffix() == "jpeg") return Image;
	if(info.suffix() == "rgb") return Image;
	if(info.suffix() == "rgba") return Image;

	if(info.suffix() == "osg") return Model;
	if(info.suffix() == "ive") return Model;
	if(info.suffix() == "flt") return Model;
	if(info.suffix() == "3ds") return Model;
    if(info.suffix() == "obj") return Model;
    if(info.suffix() == "dae") return Model;

	return Unknown;
}


void MainViewer::updateDraggedObjectPositionFromMousePosition(const QPoint& /*pos*/)
{
//	osg::Vec2 m = osg::Vec2(pos.x(), pos.y());
//	osg::Vec3 p = Snapping::snapPosition( Snapping::projectMouseToGroundPlane(m, getCamera()) );
//    m_rDraggedObject->setPosition(p);
}
